package AudioServer;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;

import org.apache.commons.logging.Log;
import org.apache.commons.net.telnet.TelnetClient;


interface MessageHandler {
	void handleMessage(String name, String message);
}

public class TelnetHandler implements Runnable {

	String host;
	int port;
	String name;
	Log log;
	MessageHandler handler;
	InputStream instr;
	OutputStream outstr;
	TelnetClient telnetClient;
	
	
	public TelnetHandler(String name, String host, int port, Log log, MessageHandler handler) {
		this.host = host;
		this.port = port;
		this.name = name;
		this.log = log;
		this.handler = handler;
		telnetClient = new TelnetClient();
		instr = null;
		outstr = null;
		this.reconnect();
	}
	
	public void sendCommand(String command) {
		log.info("Running command " + command + " on " + name);
		if (!doCommand(command)) {
    		reconnect();
    	}
	}
	
	@Override
	public void run() {
		
		while (!Thread.currentThread().isInterrupted()) {
    		// If reading the message fails for some reason, we will attempt to reconnect.
			if (!readMessage()) {
    			reconnect();
    		}
			try {
				Thread.currentThread().sleep(200);
			} catch (InterruptedException e) {
				log.info("TelnetHandler interrupted.");
			}
		}
		log.info("Disconnecting");
		try {
			telnetClient.disconnect();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			log.warn(e.toString());
			return;
		}
	}
	
	private synchronized void reconnect() {
		log.info("Reconnecting to " + name);
		try {
			telnetClient.disconnect();
		} catch (IOException e) {
			log.warn("Exception while disconnecting");
			log.warn(e.toString());
		}
		
		try {
			telnetClient.connect(host, port);
		} catch (SocketException e) {
			log.warn("Exception when connecting");
			log.warn(e.toString());
			return;
		} catch (IOException e) {
			log.warn("Exception when connecting");
			log.warn(e.toString());
			return;
		}
		
		outstr = telnetClient.getOutputStream();
		instr = telnetClient.getInputStream();
	}
	
	private synchronized boolean readMessage() {
		if (instr == null) {
			return false;
		}
		try {
			int ret_read = 0;
			int available = instr.available();
			byte[] buff = new byte[available];
			ret_read = instr.read(buff);
			if(ret_read > 0) {
				handler.handleMessage(name, new String(buff));
			}
		} catch (IOException e) {
			log.warn("Exception while reading socket:" + e.getMessage());
			return false;
		}		
		return true;
	}
	
	private synchronized boolean doCommand(String command) {
		if (outstr == null) {
			return false;
		}
		try {
    		outstr.write(("user admin admin\n" + command).getBytes());
    		outstr.flush();
		} catch (IOException e) {
			log.warn("Exception while sending command");
			log.warn(e.toString());
			return false;
		}
		return true;
	}

}
